package learn.arc.spring;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.AutoConfigurationImportSelector;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.aop.AopAutoConfiguration;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.SimpleCommandLineArgsParser;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.util.ReflectionUtils;
import sun.applet.AppletClassLoader;
import sun.misc.Launcher;
import sun.misc.URLClassPath;

import java.io.IOException;
import java.util.List;
import java.util.Set;

/**
 * @author
 * @Title:
 * @Package
 * @date 2021/10/30 22:29
 * @Description:
 */
public class SpringBoot {


    /**
     * 启动过程
     *  spring容器启动
     *  servlet容器启动
     */
    static class Start {
        /**
         * 启动类
         *  jar。
         *  war。
         */
        public static void project(){

            // war包，继承
            SpringBootServletInitializer webApplicationInitializer;
            // jar包
            SpringApplication app;

            // 启动项目
            SpringApplication.run((Class)null, null);

        }

        /**
         * spring ioc启动
         */
        public static void iocStart(){
            // main线程为守护线程，有其他线程运行时不终止
            SpringApplication.run((Class)null, null);
            {
                // 1，创建实例
                SpringApplication app = new SpringApplication((Class<?>[]) null);
                {
                    // 设置resourceLoader、primarySources等

                    // 按类路径判定应用类型；
                    WebApplicationType.deduceFromClasspath();
                    // springboot spi加载并实例化上下文刷新前回调、监听器
                    app.getSpringFactoriesInstances(ApplicationContextInitializer.class);
                    // 构建异常，获取主类
                    app.deduceMainApplicationClass();
                }
                // 2，创建上下文，运行应用
                app.run("");
                {
                    // 1，设置java.awt.headless模式；是否有显示设备，默认true
                    // https://blog.csdn.net/wodeyuer125/article/details/50502914
                    // 2，spi获取run方法监听器，触发start事件
                    SpringApplicationRunListeners listeners = app.getRunListeners(args);
                    SpringApplicationRunListener listener;
                    // 3，解析命令行参数；--解析为k-v对，构建PropertySource
                    ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
                    new SimpleCommandLineArgsParser().parse("");
                    // 4，传入applicationArguments，
                    ConfigurableEnvironment environment = app.prepareEnvironment(null, applicationArguments);
                    {
                        // 1，创建Environment
                        // 2，添加defaultProperties、commandLineProperties
                        app.configureEnvironment(environment, applicationArguments);
                        // 3，全部PropertySource封装为configurationPropertySources，供占位符解析
                        ConfigurationPropertySources.attach(environment);
                        // 4，环境准备完毕事件
                        // 5，environment绑定到app，使用其属性
                        app.bindToSpringApplication(environment);
                    }
                    // 5，配置忽略的beanInfo
                    app.configureIgnoreBeanInfo(environment);
                    // 6，打印banner
                    Banner printedBanner = app.printBanner(environment);
                    // 7，创建上下文
                    ConfigurableApplicationContext context = app.createApplicationContext();
                    AnnotationConfigServletWebServerApplicationContext contextClass;
                    {
                        // 1，按webApplicationType选择上下文类型
                        // 2，反射实例化
                        context=(ConfigurableApplicationContext) BeanUtils.instantiateClass(null);
                    }
                    // 8，上下文刷新前准备，加载BeanDefinition
                    app.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
                    {
                        // 1，设置environment
                        // 2，设置相关处理类；beanNameGenerator、resourceLoader、类型转换等
                        app.postProcessApplicationContext(context);
                        // 3，上下文刷新前回调，ApplicationContextInitializer
                        // 构造器中，spi加载
                        app.applyInitializers(context);
                        // 4，监听器contextPrepared事件
                        // 5，BeanFactory注册特殊的bean；设置BeanDefinition覆盖
                        // springApplicationArguments、springBootBanner
                        // 6，添加懒加载BeanFactoryPostProcessor
                        context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
                        // 7，加载BeanDefinition
                        Set<Object> sources = app.getAllSources();
                        {
                            // primarySources，SpringApplication构造器传入的类
                            // sources，扫描路径
                        }
                        app.load(context, sources.toArray(new Object[0]));
                        {
                            // 1，创建loader，通过BeanDefinitionRegistry直接加入BeanDefinition
                            BeanDefinitionLoader loader = app.createBeanDefinitionLoader(app.getBeanDefinitionRegistry(context), sources);
                            BeanDefinitionRegistry beanDefinitionRegistry;
                            // 2，设置beanNameGenerator、resourceLoader、environment
                            // 3，加载
                            loader.load();
                            loader.load((Object)null);// 策略模式加载
                        }
                        // 8，监听器contextLoaded事件
                    }
                    // 9，刷新上下文
                    app.refreshContext(context);
                    {
                        // 1，刷新上下文
                        app.refresh(context);
                        // 2，Runtime注册关闭时回调
                        ((AbstractApplicationContext)context).registerShutdownHook();
                        ((AbstractApplicationContext)context).doClose();// 注册的回调方法
                        Runtime.getRuntime().addShutdownHook(null);
                    }
                    // 10，刷新后回调；暂为空方法
                    app.afterRefresh(context, applicationArguments);
                    // 11，监听器started事件
                    // 12，排序后调用ApplicationRunner、CommandLineRunner
                    app.callRunners(context, applicationArguments);
                    // 13，监听器running事件


                }


            }
        }

        /**
         * servlet容器启动
         */
        public static void servletStart() {

            AnnotationConfigServletWebServerApplicationContext context=null;
            context.onRefresh();
            WebServer webServer = context.createWebServer();// 创建tomcat
        }
    }

    /**
     * 创建对象
     *  new、工厂方法
     *  spi
     *  包扫描
     *  bean。refresh后构建对象
     *
     */
    static class CreateObj{

        /**
         * 加载 META-INF/spring.factories
         *
         */
        public static void spi() throws Exception {
            List<SpringApplicationRunListener> listeners = SpringFactoriesLoader.loadFactories(SpringApplicationRunListener.class, null);
            // 加载classpath resource
            ClassLoader cl=null;
            cl.getResource("");
            cl.getResources("");
            {
                /*
                 * 存储classLoader加载路径
                 *  bootstrap。java/jre/lib下的jar包路径
                 *  ext。java/jre/lib/ext下的jar包路径
                 *  app。class路径以及引用的jar包路径；顺序？
                 */
                URLClassPath ucp;

                Launcher launcher=Launcher.getLauncher();
                // bootstrap；C++实现。System.getProperty("sun.boot.class.path")
                Launcher.BootClassPathHolder holder;
                URLClassPath bootstrapClassPath = Launcher.getBootstrapClassPath();
                // System.getProperty("java.ext.dirs")
                Launcher.ExtClassLoader ext;
                ClassLoader extClassLoader = launcher.getClassLoader().getParent();
                // System.getProperty("java.class.path")
                // 顺序：本项目；pom依赖
                Launcher.AppClassLoader app=ClassLoader.getSystemClassLoader();
                ClassLoader appClassLoader = launcher.getClassLoader();

            }

            // 加载类
            Class.forName("");

            // 创建对象。无参构造器
            ReflectionUtils.accessibleConstructor(null).newInstance();
            // 没有无参构造器；需传入参数。getRunListeners
            new SpringApplication(SpringBoot.class).run();
        }

        /**
         *
         */
        public static void scan(){

        }

        /**
         * @Import注册特殊类型BeanDefinition
         * ConfigurationClassPostProcessor，处理对应特殊类型；
         *  spi加载classFullName，注册BeanDefinition
         *
         */
        public static void autowire(){

            // springboot spi机制
            SpringFactoriesLoader springFactoriesLoader;

            // Import导入机制
            Spring.importAnno();

            // 自动配置，Import实现，spi加载classFullName，注册BeanDefinition
            EnableAutoConfiguration enableAutoConfiguration;
            AutoConfigurationImportSelector autoConfigurationImportSelector;

        }

    }

    /**
     *
     */
    static class Aop{
        public static void aop(){
            // spring 启用aop
            EnableAspectJAutoProxy enableAspectJAutoProxy;
            // springboot 启用aop；间接调用EnableAspectJAutoProxy，默认cglib
            AopAutoConfiguration aopAutoConfiguration;
        }

    }

}
